import { instantiate, isValid, Prefab, Node, find } from "cc";
import { BCPanelBase } from "../component/UIBase/BCPanelBase";
import { BCToastBase } from "../component/UIBase/BCToastBase";
import { BCViewBase } from "../component/UIBase/BCViewBase";
import { BCProjectDefines } from "../utils/BCProjectDefines";
import { BCFixedScreen } from "../component/UIBase/BCFixedScreen";
import { BCGameLog } from "../utils/BCGameLog";
import { BCResourcesMgr } from "./BCResourcesMgr";

const LogTag: string = "[BCViewMgr]";

/**
 * 展示参数类型
 */
export class BCViewParamsType {
	mode?: BCProjectDefines.ResCacheMode = BCProjectDefines.ResCacheMode.Normal;		// 缓存模式
	zIndex?: number = 999;						// 界面渲染层级，越大越上层
	parent?: Node = null;
}

/**
 * 界面展示请求类型
 */
class ViewRequestType {
	path: string;				// 预制体在resources的路径
	options: any;				// 选项
	params: BCViewParamsType;		// 缓存模式
	view?: BCViewBase|BCPanelBase;			// 组件
	node?: Node;				// 节点
	isBundle?: boolean			//是否为bundle的子界面
}

export class BCViewMgr {
	private static m_instance: BCViewMgr = null;

	private m_prefabCache: Map<string, Prefab> = new Map<string, Prefab>();															//预制体缓存
	private m_nodeCache: Map<string, Node> = new Map<string, Node>();																//节点缓存
	private m_viewQueue: Map<string, ViewRequestType> = new Map<string, ViewRequestType>();											//需要展示的界面队列	

	private constructor() {

	}

	static get instance(): BCViewMgr {
		if (!this.m_instance) {
			this.m_instance = new BCViewMgr();
		}
		return this.m_instance;
	}

	showText(text: string, path: string){
		this.getPrefab(path, false).then(prefab=>{
			const node = instantiate(prefab);
			const parent = find("Canvas");
			node.parent = parent;
			// 显示在最上层
			node.setSiblingIndex(1000);
			node.getComponent(BCToastBase)._showToast(text);
		}).catch(()=>{});
	}

	private _createView<Options>(path: string, options: Options, params: BCViewParamsType, isBundle?: boolean, bundleName?: string): Promise<void> {
		// 保存该界面，阻止重复请求
		const viewRequest: ViewRequestType = { path: path, options: options, params: params };
		this.m_viewQueue.set(path, viewRequest);
		return new Promise(async (res, reject)=>{
			// 先在缓存中获取界面节点
			let node = this.getNodeFromCache(path);
			// 缓存中没有，动态加载预制体资源
			if (!node) {
				try {
					const prefab = await this.getPrefab(path, isBundle, bundleName);
					node = instantiate(prefab); 
					this._initView(node, viewRequest, options, params);	
				} catch (error) {
					BCGameLog.error(LogTag, '界面加载失败:', path);
					this.m_viewQueue.delete(path);
				}
			} else {
				this._initView(node, viewRequest, options, params);
			}
			
			res();
		});
	}

	private _initView<Options>(viewNode: Node, viewRequest: ViewRequestType, options: Options, params: BCViewParamsType){
		// 获取继承自 ViewBase 的界面组件
		const view = viewNode.getComponent(BCViewBase);
		if (!view) {
			const panel = viewNode.getComponent(BCPanelBase);
			if (!panel) {
				BCGameLog.error(LogTag, `${viewRequest.path}未绑定BCPanelBase|BCViewBase组件`);
				this.m_viewQueue.delete(viewRequest.path);
				return;
			}
			viewRequest.view = panel;
		} else {
			viewRequest.view = view;
		}
		viewRequest.view._resetView();
		// 保存节点引用
		viewRequest.node = viewNode;
		// 添加到场景中
		viewNode.parent = params.parent;
		// 显示在最上层
		viewNode.setSiblingIndex(params.zIndex);
		// 设置完成回调
		viewRequest.view._viewClosedCallback = () => {
			//从队列中移除
			this.m_viewQueue.delete(viewRequest.path);
			// 回收
			this.recycleView(viewRequest, params);
		}
		// 展示
		viewRequest.view._showView(options);
	}


	/**
	 * 添加界面
	 * @param path 界面预制体相对路径（如：prefabs/MyView）
	 * @param options 界面选项（将传递给界面的组件）
	 * @param params 界面展示参数
	 */
	public async addView<Options>(path: string, options?: Options, params?: BCViewParamsType): Promise<void> {
		const canvas = find("Canvas");
		path = this._getConvertPath(path, canvas);
		BCGameLog.log(LogTag, `addView:${path}`);
		// 加入队列
		if (this.m_viewQueue.get(path)) {
			BCGameLog.warn(LogTag, `界面已存在，请勿重复添加:${path}`);
			return;
		}
		params = this.parseParams(params);				// 解析处理参数
		!params.parent && (params.parent = canvas);

		return new Promise(async (res)=>{
			await this._createView(path, options, params, false);
			res();
		});
	}

	public async addBundleView<Options>(bundleName: string, path: string, options?: Options, params?: BCViewParamsType): Promise<void> {
		const canvas = find("Canvas");
		path = this._getConvertPath(path, canvas);
		BCGameLog.log(LogTag, `addView:${path}`);
		// 加入队列
		if (this.m_viewQueue.get(path)) {
			BCGameLog.warn(LogTag, `界面已存在，请勿重复添加:${path}`);
			return;
		}
		params = this.parseParams(params);				// 解析处理参数
		!params.parent && (params.parent = canvas);

		return new Promise(async (res) => {
			await this._createView(path, options, params, true, bundleName);
			res();
		});
	}

	/**
	 * 解析参数
	 * @param params 参数
	 */
	private parseParams(params: BCViewParamsType) {
		if (params == undefined || Object.prototype.toString.call(params) !== '[object Object]') {
			BCGameLog.log(LogTag, '界面参数无效，使用默认参数');
			return new BCViewParamsType();
		}
		// 缓存模式
		if (params.mode == undefined) {
			params.mode = BCProjectDefines.ResCacheMode.Normal;
		}
		// 渲染层级
		if (params.zIndex == undefined) {
			params.zIndex = 999;
		}
		return params;
	}

	/**
	 * 加载并缓存界面预制体资源
	 * @param path 预制体路径
	 */
	private async getPrefab(path: string, isBundle: boolean, bundleName?: string): Promise<Prefab> {
		return new Promise(async res=>{
			let prefab = this.m_prefabCache.get(path);
			if (!prefab) {
				if (isBundle) {
					prefab = await BCResourcesMgr.getBundleResWithPath(bundleName, path, Prefab);
				} else {
					prefab = await BCResourcesMgr.getResWithPath(path, Prefab);
				}
				this.m_prefabCache.set(path, prefab);
			} else {
				// 缓存是否有效
				if (!isValid(prefab)) {
					this.m_prefabCache.delete(path);	// 删除无效引用
					prefab = await BCResourcesMgr.getResWithPath(path, Prefab);
					this.m_prefabCache.set(path, prefab);
				}
			}
			res(prefab);
		});
	}


	/**
	 * 尝试释放界面资源（注意：弹窗内部动态加载的资源请自行释放）
	 * @param path 弹窗路径
	 */
	private releaseView(path: string) {
		// 移除节点
		const nodeCache = this.m_nodeCache;
		let node = nodeCache.get(path);
		if (node) {
			nodeCache.delete(path);
			if (isValid(node)) {
				node.destroy();
			}
			node = null;
		}
		// 移除预制体
		const prefabCache = this.m_prefabCache;
		let prefab = prefabCache.get(path);
		if (prefab) {
			// 删除缓存
			if (prefab.refCount <= 1) {
				prefabCache.delete(path);
			}
			// 减少引用
			prefab.decRef();
			prefab = null;
		}
	}

	/**
	 * 回收界面
	 * @param path 预制体路径
	 * @param node 界面节点
	 * @param mode 缓存模式
	 */
	private recycleView(viewRequest: ViewRequestType, params: BCViewParamsType) {
		switch (params.mode) {
			// 一次性
			case BCProjectDefines.ResCacheMode.Once: {
				this.m_nodeCache.delete(viewRequest.path);
				viewRequest.node.destroy();
				// 释放
				this.releaseView(viewRequest.path);
				break;
			}
			// 正常
			case BCProjectDefines.ResCacheMode.Normal: {
				this.m_nodeCache.delete(viewRequest.path);
				viewRequest.node.destroy();
				break;
			}
			// 频繁
			case BCProjectDefines.ResCacheMode.Frequent: {
				viewRequest.node.parent = null;
				this.m_nodeCache.set(viewRequest.path, viewRequest.node);
				break;
			}
		}
	}

	/**
	 * 从缓存中获取节点
	 * @param path 预制体路径
	 */
	private getNodeFromCache(path: string): Node {
		// 从节点缓存中获取
		const node = this.m_nodeCache.get(path);
		if (node) {
			if (isValid(node)) {
				return node;
			} else {
				this.m_nodeCache.delete(path); 			// 删除无效引用
			}
		}
		return null;
	}

	/**
	 * 关闭界面
	 */
	async closeView(path: string) {
		path = this._getConvertPath(path)
		const viewRequest = this.m_viewQueue.get(path);
		if (viewRequest && viewRequest.view) {
			await viewRequest.view._closeView();
		}
	}
	
	// 获取view的竖屏版路径，没有的话返回原路径
	private _getConvertPath(path: string, canvas?: Node): string {
		// if(!canvas){
		// 	canvas = find("Canvas");
		// }
		// const screenConfig = canvas.getComponent(BCFixedScreen);
		// if (screenConfig.screenOrientation == BCProjectDefines.ScreenOrientation.Portrait) {
		// 	const tmp = path.split('/');
		// 	const prefabName = tmp[tmp.length-1];
		// 	if (GM.PortraitViewsTag[prefabName]){
		// 		path += "_Portrait";
		// 	}
		// 	return path;
		// }
		return path
	}
}

